﻿using System;
using MemoryPack;
#if UNITY_EDITOR
using Sirenix.OdinInspector;
#endif

namespace Hsenl {
    // 阶段, 所以子节点并行执行
    // 如果时间没到, 或者是无限时间, 则返回running
    // 相反, 则返回failure, 同时设为passed为true, 该阶段后续将不会再被执行
    [Serializable]
    [MemoryPackable]
    public partial class Stage : ParallelNode<ITimeLine, ITimeNode>, IStageNode {
#if UNITY_EDITOR
        [ShowInInspector, PropertyOrder(-1)]
#endif
        [MemoryPackInclude]
        public int StageType { get; set; }

#if UNITY_EDITOR
        [ShowInInspector, PropertyOrder(-1)]
#endif
        [MemoryPackInclude]
        public float Duration { get; set; }

#if UNITY_EDITOR
        [PropertyOrder(-1)]
#endif
        [MemoryPackIgnore]
        public bool passed;

        [MemoryPackIgnore]
        protected StageLine stageLine;

        protected sealed override void OnNodeRunningStart() { }
        protected sealed override void OnNodeRunningEnd() { }

        protected sealed override void OnAwake() {
            this.stageLine = this.manager as StageLine;
        }

        protected sealed override void OnReset() {
            this.passed = false;
        }

        protected sealed override bool OnNodeEvaluate() {
            var b = this.stageLine != null && !this.passed;
            if (b) {
                // 当阶段刚开始时, 初始化自己的值
                if (this.NowStatus != NodeStatus.Running) {
                    this.manager.Time = 0;
                    this.manager.TillTime = this.Duration;
                    this.stageLine.CurrentStage = this.StageType;
                }
            }

            return b;
        }

        protected sealed override NodeStatus OnNodeTick() {
            var ret = base.OnNodeTick();
            // 除非下面的节点return 或 break了, 否则一律继续执行, 因为阶段的任务是把时间跑完, 其下的节点的成功与否都不会影响阶段的运行.
            if (ret is NodeStatus.Return or NodeStatus.Break)
                return ret;

            return NodeStatus.Running;
        }

        protected sealed override void OnNodeRunning() {
            if (this.manager.TillTime < 0) {
                return;
            }

            if (this.manager.Time >= this.manager.TillTime) {
                this.passed = true;
            }
        }
    }
}